#pragma once

#include "Sock.hpp"


#define DFL_PORT 8080
#define NUM (sizeof(fd_set)*8)
#define DFL_FD -1

class SelectServer{
    private:
        int lsock; //listen sock
        int port;
        int fd_array[NUM];
    public:
        SelectServer(int _p = DFL_PORT):port(_p)
        {}
        void InitServer()
        {
            for(int i = 0 ; i < NUM; i++){
                fd_array[i] = DFL_FD;
            }
            lsock = Sock::Socket();
            Sock::Setsockopt(lsock);
            Sock::Bind(lsock, port);
            Sock::Listen(lsock);

            fd_array[0] = lsock;
        }
        void AddFd2Array(int sock)
        {
            int i = 0;
            for( ; i < NUM; i++){
                if(fd_array[i] == DFL_FD){
                    break;
                }
            }
            if(i >= NUM){
                cerr << "fd array is full, close sock" << endl;
                close(sock);
            }
            else{
                fd_array[i] = sock;
                cout << "fd: " << sock << " add to select ..." << endl;
            }
        }
        void DefFdFromArray(int index)
        {
            if(index >=0 && index < NUM){
                fd_array[index] = DFL_FD;
            }
        }
        void HandlerEvents(fd_set *rfds)
        {
            for(int i = 0; i < NUM; i++){
                if(fd_array[i] == DFL_FD){
                    continue;
                }

                if(FD_ISSET(fd_array[i], rfds)){
                    //read ready
                    if(fd_array[i] == lsock){
                        //link event
                        int sock = Sock::Accept(lsock);
                        if(sock >= 0){
                            //sock ok
                            cout << "get a new link ..." << endl;
                            AddFd2Array(sock);
                        }
                    }
                    else{
                        //data ready event
                        //bug!
                        char buf[10240];
                        ssize_t s= recv(fd_array[i], buf, sizeof(buf), 0);
                        if(s>0){
                            buf[s] = 0;
                            cout << "client# " << buf << endl;
                        }
                        else if(s == 0){
                            cout << "clien quit" << endl;
                            close(fd_array[i]);
                            DefFdFromArray(i);
                        }
                        else{
                            //TODO
                        }
                    }
                }
                //if(FD_ISSE(fd, wfds)){
                //}
            }
        }
        void Start()
        {
            int maxfd = DFL_FD;
            for(;;){
                //select
                fd_set rfds;
                FD_ZERO(&rfds);
                cout << "fd_array: ";
                for(int i = 0; i < NUM; i++){
                    if(fd_array[i] != DFL_FD){
                        cout << fd_array[i] << " ";
                        FD_SET(fd_array[i], &rfds);
                        if(maxfd < fd_array[i]){
                            maxfd = fd_array[i];
                        }
                    }
                }
                cout << endl;
                cout << "begin select ..." << endl;
                //struct timeval timeout = {0, 0};
                switch(select(maxfd+1, &rfds, nullptr, nullptr, /*&timeout*/nullptr)){
                    case 0:
                        cout << "timeout ..." << endl;
                        break;
                    case -1:
                        cerr << "select error!" << endl;
                        break;
                    default:
                        //success
                        HandlerEvents(&rfds);
                        break;
                }
            }
        }
        ~SelectServer()
        {}
};


